package com.sugon.controller.device;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.annotation.AutoLog;
import com.sugon.annotation.LimitSubmit;
import com.sugon.annotation.NonBusinessParamValid;
import com.sugon.entity.*;
import com.sugon.modules.alarm.service.AlarmCodeBaseService;
import com.sugon.modules.device.model.vo.PerfectDevRepairRecordParamVO;
import com.sugon.modules.device.service.IDeviceRepairManager;
import com.sugon.service.*;
import com.sugon.utils.PageUtils;
import com.sugon.utils.Query;
import com.sugon.utils.R;
import com.sugon.utils.ShiroUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;


/**
 * 维修记录单Controller
 *
 * @author sugon
 * @date 2023-03-13
 */
@Controller
@RequestMapping("devmaintenrepair")
public class DevMaintenRepairController {

    @Resource
    private DevMaintenRepairService devMaintenRepairService;
    @Resource
    private IDeviceRepairManager deviceRepairManager;
    @Resource
    private DeviceInfoService deviceService;
    @Resource
    private AlarmCategoryService alarmCategoryService;
    @Resource
    private AlarmCodeBaseService alarmCodeBaseService;
    @Resource
    private DevFaultPreventMeasureService devFaultPreventMeasureService;
    @Resource
    private TicketLiveImageService ticketLiveImageService;

    /**
     * 查看列表
     */
    @RequestMapping("/list")
//    @RequiresPermissions("devmaintenrepair:list")
    @ResponseBody
    public R list(@RequestParam Map<String, Object> params) {
        // 维修开始时间
        String beginTime = MapUtil.getStr(params, "beginTime");
        if (StrUtil.isNotEmpty(beginTime)) {
            params.put("beginTime", DateUtil.formatDateTime(DateUtil.beginOfDay(DateUtil.parseDate(beginTime))));
        }
        // 维修终止时间
        String endTime = MapUtil.getStr(params, "endTime");
        if (StrUtil.isNotEmpty(endTime)) {
            params.put("endTime", DateUtil.formatDateTime(DateUtil.endOfDay(DateUtil.parseDate(endTime))));
        }
        // 报警分类ID
        String faultCategoryId = MapUtil.getStr(params, "faultCategoryId");
        if (StrUtil.isNotEmpty(faultCategoryId)) {
            AlarmCategoryEntity alarmCategory = alarmCategoryService.queryObject(faultCategoryId);
            if (alarmCategory != null) {
                params.put("alarmCode", alarmCategory.getCode());
            }
        }
        //查询列表数据
        Query query = new Query(params);
        List<DevMaintenRepairEntity> devMaintenRepairList = devMaintenRepairService.queryList(query);
        int total = devMaintenRepairService.queryTotal(query);
        PageUtils pageUtil = new PageUtils(devMaintenRepairList, total, query.getLimit(), query.getPage());
        return R.ok().put("page", pageUtil);
    }

    /**
     * 查看信息
     */
    @RequestMapping("/info/{id}")
    @ResponseBody
    public R info(@PathVariable("id") String id) {
        DevMaintenRepairEntity repairRecord = devMaintenRepairService.queryObject(id);
        if (repairRecord == null) {
            return R.error("设备维修记录不存在，请确认！");
        }
        // 设置设备报警分类：大类、种类、小类的ID
        if (StrUtil.isNotEmpty(repairRecord.getFaultCategoryId())) {
            List<String> alarmCatetoryIdList = alarmCategoryService.listBMS(repairRecord.getFaultCategoryId());
            if (CollectionUtil.isNotEmpty(alarmCatetoryIdList)) {
                for (int i = 0; i < alarmCatetoryIdList.size(); i++) {
                    if (i == 0) {
                        repairRecord.setVrtId(alarmCatetoryIdList.get(i));
                    } else if (i == 1) {
                        repairRecord.setVfgId(alarmCatetoryIdList.get(i));
                    } else if (i == 2) {
                        repairRecord.setFaultCategoryId(alarmCatetoryIdList.get(i));
                    }
                }
            }
        }
        // 获取设备故障预防措施列表
        repairRecord.setPreventMeasureList(devFaultPreventMeasureService.queryByRepairTicketId(repairRecord.getMaintenRecordId()));
        // 设置下现场照片
        repairRecord.setFaultImages(ticketLiveImageService.getTicketLiveImages("维修前",repairRecord.getMaintenRecordId(),"REPAIR"));
        return R.ok().put("devMaintenRepair", repairRecord);
    }

    /**
     * 维修工单-完善维修记录
     */
    @LimitSubmit(key = "perfectRepairRecord:%s")
    @NonBusinessParamValid
    @AutoLog("设备维修工单-完善维修记录")
    @RequestMapping("/save")
//    @RequiresPermissions("devmaintenrepair:save")
    @ResponseBody
    public R save(@Validated @RequestBody PerfectDevRepairRecordParamVO repairRecordParam, BindingResult bindingResult) {
        // 维修记录ID必填
        String repairRecordId = repairRecordParam.getId();
        if (StrUtil.isEmpty(repairRecordId)) {
            return R.error("维修记录ID必填！");
        }
        // 校验维修记录是否存在
        DevMaintenRepairEntity repairRecordInDB = devMaintenRepairService.queryObject(repairRecordId);
        if (repairRecordInDB == null) {
            return R.error("维修记录不存在，请确认！");
        }
        // 校验设备是否存在
        DeviceInfoEntity device = deviceService.queryObject(repairRecordParam.getDevId());
        if (device == null) {
            return R.error("设备不存在，请确认！");
        }
        // 校验设备报警分类是否存在
        AlarmCategoryEntity alarmCategory = alarmCategoryService.queryObject(repairRecordParam.getFaultCategoryId());
        if (alarmCategory == null) {
            return R.error("设备报警故障分类不存在，请确认！");
        }
        /*
            1、开始维修时间和开始结束时间不得早于当前系统时间
            2、开始维修时间不能晚于结束维修时间
         */
        DateTime current = DateUtil.date();
        if (repairRecordParam.getRepairStartDate().after(current)) {
            return R.error("维修开始时间不得晚于当前系统时间！");
        }
        if (repairRecordParam.getRepairEndDate().after(current)) {
            return R.error("维修结束时间不得晚于当前系统时间！");
        }
        if (repairRecordParam.getRepairStartDate().after(repairRecordParam.getRepairEndDate())) {
            return R.error("维修开始时间不得晚于维修结束时间！");
        }
        // 维修时长必须大于5分钟
        if (DateUtil.between(repairRecordParam.getRepairStartDate(), repairRecordParam.getRepairEndDate(), DateUnit.MINUTE) < 5) {
            return R.error("维修时长不得小于5分钟！");
        }

        // 校验如果填写故障预防措施的话，必填校验和日期先后校验
        List<DevFaultPreventMeasure> measureList = repairRecordParam.getPreventMeasureList();
        if (CollectionUtil.isNotEmpty(measureList)) {
            for (DevFaultPreventMeasure measure : measureList) {
                if (!ObjectUtil.isAllNotEmpty(measure.getContent(), measure.getStartDate(), measure.getEndDate())) {
                    return R.error("制定措施时，措施内容、开始时间和结束时间必填！");
                }
                // 开始维修时间不能晚于结束维修时间
                if (measure.getStartDate().after(measure.getEndDate())) {
                    return R.error("预防措施开始时间不得晚于结束时间！");
                }
            }
            repairRecordInDB.setPreventMeasureList(measureList);
        }

        /*
            如果设备报警库ID没填，说明是新增的
                校验下指定设备，特定的报警分类下是否存在这个报警代码
                    如果存在，则直接提示已存在
                    如果不存在，则创建并返回
            如果填写了，需要跟报警代码和
         */
        AlarmCodeBaseEntity alarmCodeBase;
        String faultId = repairRecordParam.getFaultId();
        if (StrUtil.isNotEmpty(faultId)) {
            alarmCodeBase = alarmCodeBaseService.queryObject(faultId);
            if (alarmCodeBase == null) {
                return R.error("当前设备报警代码库不存在，请确认！");
            }
            // 校验是否是这个设备的
            if (!repairRecordParam.getDevId().equals(alarmCodeBase.getDevId())) {
                return R.error("当前设备报警不是这个设备的，请确认！");
            }
            // 校验是否是这个报警分类下的
            if (!repairRecordParam.getFaultCategoryId().equals(alarmCodeBase.getAlarmCategoryId())) {
                return R.error("当前设备报警不属于这个报警分类，请确认！");
            }
            repairRecordParam.setFaultCode(alarmCodeBase.getAlarmCode());
            repairRecordParam.setFaultDesc(alarmCodeBase.getAlarmDesc());
        } else {
            // 必填校验
            if (StrUtil.isEmpty(repairRecordParam.getFaultCode())) {
                return R.error("报警代码必填！");
            }
             /*
                理论上：一台设备不管分为多少个部位，报警代码是唯一的
                手动新增时需要区分报警代码已存在和不存在的情形：
                9999：不存在，通用代码
                9999之外的其他情形：
             */
            if (!"9999".equals(repairRecordParam.getFaultCode())) {
                // 获取匹配的设备报警库。如果不存在，则创建
                alarmCodeBase = alarmCodeBaseService.query(null, repairRecordParam.getDevId(), repairRecordParam.getFaultCode());
                if (alarmCodeBase != null) {
                    return R.error("当前设备报警代码[{}]已关联报警分类：[{}]，无需重复录入！", repairRecordParam.getFaultCode(), alarmCodeBase.getTreeName());
                }
            }
            alarmCodeBase = alarmCodeBaseService.queryOrCreateIfNotExists(repairRecordParam.getFaultCategoryId(), repairRecordParam.getDevId(), repairRecordParam.getFaultCode(), repairRecordParam.getFaultDesc(), true);
        }
        CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true).setIgnoreProperties("measureList", "maintenRecordId");
        BeanUtil.copyProperties(repairRecordParam, repairRecordInDB, copyOptions);
        repairRecordInDB.setFaultId(alarmCodeBase.getId());
        repairRecordInDB.setFaultCategoryId(repairRecordParam.getFaultCategoryId());
        // 设置故障时间
        repairRecordInDB.setFaultNum(DateUtil.between(repairRecordInDB.getRepairStartDate(), repairRecordInDB.getRepairEndDate(), DateUnit.MINUTE));
        // 如果维修人员为空，那么默认当前完善维修记录的就是维修人员
        if (StrUtil.isEmpty(repairRecordInDB.getRepairUser())) {
            repairRecordInDB.setRepairUser(ShiroUtils.getUserId());
        }
        repairRecordInDB.setWorkshopId(device.getDevFarm());
        return deviceRepairManager.perfectRepairRecord(repairRecordInDB) ? R.ok() : R.error();
    }

    /**
     * 补录维修记录，用于后补维修记录的场景
     */
    @LimitSubmit(key = "doAdditionalRecording:%s")
    @NonBusinessParamValid
    @AutoLog("设备维修记录-补录维修记录")
    @RequestMapping("/addRepairRecord")
    @RequiresPermissions("devmaintenrepair:save")
    @ResponseBody
    public R addRepairRecord(@Validated @RequestBody PerfectDevRepairRecordParamVO repairRecord, BindingResult bindingResult) {
        // 校验设备是否存在
        DeviceInfoEntity device = deviceService.queryObject(repairRecord.getDevId());
        if (device == null) {
            return R.error("设备不存在，请确认！");
        }
        // 校验设备报警分类是否存在
        AlarmCategoryEntity alarmCategory = alarmCategoryService.queryObject(repairRecord.getFaultCategoryId());
        if (alarmCategory == null) {
            return R.error("设备报警故障分类不存在，请确认！");
        }
        /*
            1、开始维修时间和开始结束时间不得早于当前系统时间
            2、开始维修时间不能晚于结束维修时间
         */
        DateTime current = DateUtil.date();
        if (repairRecord.getRepairStartDate().after(current)) {
            return R.error("维修开始时间不得晚于当前系统时间！");
        }
        if (repairRecord.getRepairEndDate().after(current)) {
            return R.error("维修结束时间不得晚于当前系统时间！");
        }
        if (repairRecord.getRepairStartDate().after(repairRecord.getRepairEndDate())) {
            return R.error("维修开始时间不得晚于维修结束时间！");
        }
        // 维修时长必须大于5分钟
        if (DateUtil.between(repairRecord.getRepairStartDate(), repairRecord.getRepairEndDate(), DateUnit.MINUTE) < 5) {
            return R.error("维修时长不得小于5分钟！");
        }
        /*
            如果设备报警库ID没填，说明是新增的
                校验下指定设备，特定的报警分类下是否存在这个报警代码
                    如果存在，则直接提示已存在
                    如果不存在，则创建并返回
            如果填写了，需要跟报警代码和
         */
        AlarmCodeBaseEntity alarmCodeBase;
        String faultId = repairRecord.getFaultId();
        if (StrUtil.isNotEmpty(faultId)) {
            alarmCodeBase = alarmCodeBaseService.queryObject(faultId);
            if (alarmCodeBase == null) {
                return R.error("当前设备报警代码库不存在，请确认！");
            }
            // 校验是否是这个设备的
            if (!repairRecord.getDevId().equals(alarmCodeBase.getDevId())) {
                return R.error("当前设备报警不是这个设备的，请确认！");
            }
            // 校验是否是这个报警分类下的
            if (!repairRecord.getFaultCategoryId().equals(alarmCodeBase.getAlarmCategoryId())) {
                return R.error("当前设备报警不属于这个报警分类，请确认！");
            }
            repairRecord.setFaultCode(alarmCodeBase.getAlarmCode());
            repairRecord.setFaultDesc(alarmCodeBase.getAlarmDesc());
        } else {
            /*
                理论上：一台设备不管分为多少个部位，报警代码是唯一的
                手动新增时需要区分报警代码已存在和不存在的情形：
                9999：不存在，通用代码
                9999之外的其他情形：
             */
            if (!"9999".equals(repairRecord.getFaultCode())) {
                // 获取匹配的设备报警库。如果不存在，则创建
                alarmCodeBase = alarmCodeBaseService.query(null, repairRecord.getDevId(), repairRecord.getFaultCode());
                if (alarmCodeBase != null) {
                    return R.error("当前设备报警代码[{}]已关联报警分类：[{}]，无需重复录入！", repairRecord.getFaultCode(), alarmCodeBase.getTreeName());
                }
            }
            alarmCodeBase = alarmCodeBaseService.queryOrCreateIfNotExists(repairRecord.getFaultCategoryId(), repairRecord.getDevId(), repairRecord.getFaultCode(), repairRecord.getFaultDesc(), true);
        }
        DevMaintenRepairEntity devRepairRecord = new DevMaintenRepairEntity();
        BeanUtil.copyProperties(repairRecord, devRepairRecord);
        devRepairRecord.setFaultId(alarmCodeBase.getId());
        devRepairRecord.setFaultCategoryId(repairRecord.getFaultCategoryId());
        // 设置故障时间
        devRepairRecord.setFaultNum(DateUtil.between(devRepairRecord.getRepairStartDate(), devRepairRecord.getRepairEndDate(), DateUnit.MINUTE));
        devRepairRecord.setRepairUser(ShiroUtils.getUserId());
        devRepairRecord.setWorkshopId(device.getDevFarm());
        deviceRepairManager.doAdditionalRecording(devRepairRecord);
        return R.ok();
    }

    /**
     * 修改
     */
    @AutoLog("更新维修记录")
    @RequestMapping("/update")
    @RequiresPermissions("devmaintenrepair:update")
    @ResponseBody
    public R update(@RequestBody DevMaintenRepairEntity devMaintenRepair) {
        // 设置故障时间
        devMaintenRepair.setFaultNum(DateUtil.between(devMaintenRepair.getRepairStartDate(), devMaintenRepair.getRepairEndDate(), DateUnit.MINUTE));
        devMaintenRepairService.update(devMaintenRepair);
        return R.ok();
    }

    /**
     * 删除
     */
    @AutoLog("删除维修记录")
    @RequestMapping("/delete")
    @RequiresPermissions("devmaintenrepair:delete")
    @ResponseBody
    public R delete(@RequestBody String[] ids) {
        devMaintenRepairService.deleteBatch(ids);

        return R.ok();
    }

    /**
     * 查看所有列表
     */
    @RequestMapping("/queryAll")
    @ResponseBody
    public R queryAll(@RequestParam Map<String, Object> params) {

        List<DevMaintenRepairEntity> list = devMaintenRepairService.queryList(params);

        return R.ok().put("list", list);
    }

}
